import { ref, onMounted, watch, nextTick } from 'vue'
import type { Ref } from 'vue'
import { throttle } from '@/utils/behaviorcontrol'

interface Config {
    data: any // 数据源（需包含唯一id）
    scrollContainer: string // 滚动容器选择器
    actualHeightContainer: string // 实际高度容器
    translateContainer: string // 偏移容器
    itemContainer: string // 列表项选择器
    itemHeight: number // 预估高度
    size: number // 渲染数量
}

type HtmlElType = HTMLElement | null

export function useVirtualList(config: Config) {
    let actualHeightContainerEl: HtmlElType = null, // 所有信息的容器
        translateContainerEl: HtmlElType = null, // 视口容器
        scrollContainerEl: HtmlElType = null // 滚动容器

    // 数据源
    let dataSource: any[] = []
    // 累积高度
    let cumulativeHeights: number[] = [0]
    // 更新渲染数据和偏移
    const actualRenderData: Ref<any[]> = ref([])
    // 增加挂载状态标记
    const isMounted = ref(false)
    // 缓存项高度（使用唯一id）
    const renderedItemsCache: Record<string, number> = {}
    // 额外加载项(缓冲区)
    const BUFFER_SIZE = 3
    // 滚动位置记忆
    const scrollPositionMemory = ref<{ top: number; clientHeight: number } | null>(null)
    // 尺寸监听
    const observer = ref<ResizeObserver>()

    // 更新累积高度数组
    const updateCumulativeHeights = () => {
        cumulativeHeights = [0]
        let sum = 0
        dataSource.forEach((item) => {
            sum += renderedItemsCache[item.id] || config.itemHeight
            cumulativeHeights.push(sum)
        })
    }

    // 二分查找定位索引
    const binarySearch = (target: number): number => {
        // 聊天信息的数量
        let low = 0,
            high = dataSource.length
        while (low <= high) {
            const mid = Math.floor((low + high) / 2)
            if (cumulativeHeights[mid] <= target) {
                low = mid + 1
            } else {
                high = mid - 1
            }
        }
        return high
    }

    // 带缓冲区的渲染数据获取
    const updateRenderData = (scrollTop: number) => {
        const totalHeight = cumulativeHeights[cumulativeHeights.length - 1]
        const containerHeight = scrollContainerEl?.clientHeight || 0
        const adjustedScrollTop = totalHeight - scrollTop - containerHeight

        const foundIndex = binarySearch(adjustedScrollTop)
        const startIndex = Math.max(0, foundIndex - BUFFER_SIZE)
        const endIndex = Math.min(foundIndex + config.size + BUFFER_SIZE, dataSource.length)

        actualRenderData.value = dataSource.slice(startIndex, endIndex)
        updateOffset(totalHeight - cumulativeHeights[endIndex])
    }

    // 平滑动画
    const updateOffset = (offset: number) => {
        if (!translateContainerEl) return

        translateContainerEl.style.transition =
            'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)'
        translateContainerEl.style.transform = `translateY(${offset}px)`

        // 清除过渡效果
        setTimeout(() => {
            translateContainerEl!.style.transition = ''
        }, 300)
    }

    const initResizeObserver = () => {
        observer.value = new ResizeObserver((entries) => {
            entries.forEach((entry) => {
                const target = entry.target as HTMLElement
                const index = parseInt(target.dataset.index || '0')
                const newHeight = entry.contentRect.height

                if (renderedItemsCache[dataSource[index].id] !== newHeight) {
                    renderedItemsCache[dataSource[index].id] = newHeight
                    updateCumulativeHeights()
                    updateActualHeight()
                    updateRenderData(scrollContainerEl?.scrollTop || 0)
                }
            })
        })
    }

    // 修改滚动处理函数
    const handleScroll = throttle((e: Event) => {
        if (!isMounted.value) return

        const target = e.target as HTMLElement
        const { scrollTop, scrollHeight, clientHeight } = target

        // 自动滚动到底部判断
        const isAtBottom = scrollHeight - (scrollTop + clientHeight) < 50
        if (isAtBottom) {
            scrollPositionMemory.value = null
        }

        updateRenderData(scrollTop)
    }, 16)

    onMounted(() => {
        // 所有信息的容器
        actualHeightContainerEl = document.querySelector(config.actualHeightContainer)
        // 视口容器
        scrollContainerEl = document.querySelector(config.scrollContainer)
        // 滚动容器
        translateContainerEl = document.querySelector(config.translateContainer)
        // 标记已挂载
        isMounted.value = true

        // 更新初始渲染的数据
        updateRenderData(0)
        scrollContainerEl?.addEventListener('scroll', handleScroll)
        initResizeObserver()
        nextTick(() => {
            if (scrollContainerEl && !scrollPositionMemory.value) {
                scrollContainerEl.scrollTop = scrollContainerEl.scrollHeight
            }
        })
    })

    // 更新实际容器高度
    const updateActualHeight = () => {
        if (!actualHeightContainerEl) return

        const totalHeight = cumulativeHeights[cumulativeHeights.length - 1]
        actualHeightContainerEl.style.height = `${totalHeight}px`
    }

    // 修改watch逻辑
    watch(
        () => config.data,
        (newVal) => {
            dataSource = newVal

            // 等待挂载完成后再执行
            nextTick(() => {
                updateCumulativeHeights()
                updateActualHeight()
                if (scrollContainerEl) {
                    updateRenderData(scrollContainerEl.scrollTop)
                }
            })
        },
        { immediate: true },
    )

    return actualRenderData
}
